#include "Pinyin.h"
#include <list>
#include <string.h>
#include <stdint.h>
#include <core/strings/pinyin.h>
#include <core/strings/pinyin_search.h>
#include <core/strings/string_convert.h>
#include <core/sync/lock.h>
#include <core/Utility.h>

typedef qb::base::Spell Spell;
namespace qb {
namespace{
	/*
        计算一个UTF8字符的长度
        返回结果
        1   表示成功，bsize有效
        0   表示不完整的UTF8字符
        -1  表示失败，无效的UTF8字符
    */
	int CalcUTF8Char(const char * buffer, int buflen, int& bsize)
	{
		bsize = 0;
		if (buffer == NULL || buflen <= 0)
			return -1;

		unsigned char uv = (unsigned char)buffer[0];
		if (uv <= 127)
		{
			bsize = 1;
			return 1;
		}

		unsigned char mask = 0x80;
		int msize = 0;
		for (msize = 0; msize < 8; ++msize)
		{
			if ((uv & mask) == 0)
				break;

			mask = mask >> 1;
		}

		int idx;
		for (idx = 1; (idx < msize) && (idx < buflen); ++idx)
		{
			uv = (unsigned char)buffer[idx];
			if ((uv & 0xc0) != 0x80)
				return -1;
		}

		if (idx != msize)
			return 0;

		bsize = msize;
		return 1;
	}
	char utf8s[256] = { 0 };
	bool ParseUTF8Stream(const std::string& utf8, std::list<std::string>& chars)
	{
		chars.clear();
		const char * str = utf8.c_str();
		int slen = (int)utf8.length(), bsize = 0;
		while (CalcUTF8Char(str, slen, bsize) == 1)
		{
			memset(utf8s, 0, 256);
			memcpy(utf8s, str, bsize);
			utf8s[bsize] = '\0';

			chars.push_back(utf8s);
			str += bsize;
			slen -= bsize;
		}

		return (chars.empty() == false);
	}

	// 仅仅使得下面代码能够编译,真实情况不会使用
	static const unsigned char utf8_pinyin_cont[] = {
        (unsigned char)'\x09', (unsigned char)'\xe3', (unsigned char)'\x80', (unsigned char)'\x87', (unsigned char)'\0',
        (unsigned char)'\x6c', (unsigned char)'\x69', (unsigned char)'\x6e', (unsigned char)'\x67', (unsigned char)'\0'
	};
	static const int PINYIN_CONT_MAX_SIZE = 2;

	static void string_ToLower(std::string &SrcString){
		for (auto i = SrcString.begin(); i != SrcString.end(); i++)
			if (*i >= 'A' && *i <= 'Z')
				*i = (*i) + ('a' - 'A');
	}

	static void string_ToUpper(std::string &SrcString){
		for (auto i = SrcString.begin(); i != SrcString.end(); i++)
			if (*i >= 'a' && *i <= 'z')
				*i = (*i) - ('a' - 'A');
	}
}
/////////////////////////////////////////////////////////////////////////////////////
class PinyinManagerImpl : public IPinyin{
	enum{BUFLENGTH=1024};
	qb::base::CConvertFast		m_converter;
	wchar_t*					m_quan_buffer;
	wchar_t*					m_jian_buffer;
	qb::base::CSLock			m_lock;
public:
	PinyinManagerImpl()
	{
		m_quan_buffer = new wchar_t[BUFLENGTH];
		m_jian_buffer = new wchar_t[BUFLENGTH];
		memset(m_quan_buffer, 0, BUFLENGTH*sizeof(wchar_t));
		memset(m_jian_buffer, 0, BUFLENGTH*sizeof(wchar_t));
	}
	~PinyinManagerImpl()
	{
		if (m_quan_buffer)	delete m_quan_buffer;
		if (m_jian_buffer)	delete m_jian_buffer;
	}
	virtual void GetPinyinBuffer(const char* buffer, wchar_t* jianbuf, int& jianlen, wchar_t* quanbuf, int& quanlen)
	{
		SCOPED_LOCK(m_lock);
		const wchar_t* name = m_converter.ToWide(buffer, strlen(buffer));
		Spell::Parse(name, m_converter.GetWstrSize(), quanbuf, quanlen, jianbuf, jianlen);
	}
	virtual void GetPinyin(const char* buffer, std::string &sJianpin, std::string &sQuanpin, IPinyin::kFlag flag)
	{
		SCOPED_LOCK(m_lock);
		int flen = BUFLENGTH-1, slen = BUFLENGTH - 1;
		m_quan_buffer[0] = 0; m_jian_buffer[0] = 0;
		if (flag == IPinyin::kFlagJian)flen = 0;
		if (flag == IPinyin::kFlagFull)slen = 0;
		const wchar_t* name = m_converter.ToWide(buffer, strlen(buffer));
		Spell::Parse(name, m_converter.GetWstrSize(), m_quan_buffer, flen, m_jian_buffer, slen);
		if (flag == IPinyin::kFlagJian || flag == IPinyin::kFlagBoth)
		{
			const char* pGBK = m_converter.ToGbk(m_jian_buffer, slen);
			sJianpin = (pGBK ? pGBK : "");
		}

		if (flag == IPinyin::kFlagFull || flag == IPinyin::kFlagBoth)
		{
			const char* pGBK = m_converter.ToGbk(m_quan_buffer, flen);
			sQuanpin = (pGBK ? pGBK : "");
		}
	}
	virtual const std::string GetPinyin(const char* buffer)
	{
		SCOPED_LOCK(m_lock);
		std::wstring name = m_converter.ToWide(buffer, strlen(buffer));
		wchar_t jian[1024] = { 0 }; 
		int flen=0,slen = 1024;
		Spell::Parse(name.c_str(), name.size(), 0, flen, jian, slen);
		const char* pGBK = m_converter.ToGbk(jian, slen);
		return (pGBK ? pGBK : "");
	}
	virtual void Dump(int select)
	{
		SCOPED_LOCK(m_lock);
	}
};

/////////////////////////////////////////////////////////////////////////////////////
/*
使用vector而不是set，主要是为了保持拼音的顺序
*/
class Pinyins : public std::vector<std::string> {
public:
	static const Pinyins EMPTY;
};

const Pinyins Pinyins::EMPTY;
/////////////////////////////////////////////////////////////////////////////////////
PinyinManager::PinyinManager() :m_impl(0)
{
	// 如果不需要使用新的实现,将如下代码行注释掉即可
	m_impl = new PinyinManagerImpl();

	//BLOGINFO("使用%s字典实现,花费%dms", newimpl ? "新" : "旧", time.elapsed().minisec());
}
PinyinManager::~PinyinManager()
{
	if (m_impl)
		delete m_impl;
}

void PinyinManager::GetPinyinBuffer(const char* buffer, wchar_t* jianbuf, int& jianlen, wchar_t* quanbuf, int& quanlen)
{
	m_impl->GetPinyinBuffer(buffer, jianbuf, jianlen, quanbuf, quanlen);
}
void PinyinManager::GetPinyin(const char* buffer, std::string &sJianpin, std::string &sQuanpin,IPinyin::kFlag flag){
	m_impl->GetPinyin(buffer, sJianpin, sQuanpin, flag);
}

const std::string PinyinManager::GetPinyin(const char* buffer){
	return m_impl->GetPinyin(buffer);
}
void PinyinManager::Dump(int select)
{
	if (m_impl)
		m_impl->Dump(select);
}
}


qb::PinyinManager& qb::PinyinManager::instance()
{
	static qb::PinyinManager s_pm;
	return s_pm;
}
